home *** CD-ROM | disk | FTP | other *** search
/ Network Supervisor's Toolkit / Network Supervisor's Toolkit.iso / perform / netframe / nx.c < prev    next >
C/C++ Source or Header  |  1996-07-10  |  27KB  |  918 lines

  1. /*
  2. $Module NX.C$
  3.  
  4. Copyright 1990
  5. By NetFRAME Systems Inc.
  6.    Sunnyvale, California U.S.A.
  7.  
  8. $Author:   Karl S. Johnson  $
  9. $Date:   03 Apr 1990 11:54:02  $
  10. $Revision:   1.2  $
  11.  
  12. $Description$
  13. This is a NetWare Loadable Module to measure network performance.
  14. $EndDescription$
  15.  
  16.  
  17.    Revision History
  18. $Log:   H:/386/NLMS/DX/SRC/VCS/NX.C  $
  19.  * 
  20.  *    Rev 1.2   03 Apr 1990 11:54:02   Karl S. Johnson
  21.  * Recode scheduler in exerciser routine to clean up and to go to
  22.  *   sleep when there is nothing to do.
  23.  * 
  24.  *    Rev 1.1   02 Apr 1990 17:15:32   Karl S. Johnson
  25.  * Various changes to make it work the first time on System Pro and NetFRAME
  26.  * 
  27.  *    Rev 1.0   21 Mar 1990 10:48:46   Walter A. Wallach
  28.  * Initial revision.
  29.  * 
  30. */
  31. #include "procdefs.h"
  32. #include "ecb.h"
  33. #include "loader.h"
  34. #include "lanconf.h"
  35. #include "random.h"
  36. #define MAX_DEVICES 16
  37. #define MAX_SENDS_PER_DEVICE 32
  38. #define DEVICES_PER_PAGE 10
  39. #define NX_PRIORITY 50
  40. #define NX_SIGNATURE "NX TEST PACKET"
  41.  
  42. #define STACK_SIZE 2048*16
  43. #define _UNUSED(x) if (0) if (x)
  44.  
  45. extern LONG NumberOfPollingLoops, MaximumNumberOfPollingLoops;
  46.  
  47. LONG NXUpdateInterval;
  48. ScreenStruct *nXerciseScreen;
  49. int DeviceCount = 0;
  50. BYTE *stack;            /* NX Monitor Stack */
  51. LONG stackSize;
  52. BYTE *NXStack = NULL;        /* NX Exerciser Stack */
  53. LONG NXActualStackSize;
  54. LONG nXerciseModuleHandle;
  55. LONG ServerProcessPriority = 50;
  56. LONG NXMonitorProcessID = 0;
  57. LONG NXerciseProcessID = 0;
  58. LONG NXChunksPerIO;
  59. LONG NXMaxSendsPerDevice;
  60. LONG NXSleeping = 0;
  61. LONG NXWakeRequested = 0;
  62. char NXMonitorStatus = 'I'; /* Possible Status I=Initializing R=Running P=Pending Stop S=Stopped */
  63. eventcontrolblock *ECBList = NULL;
  64. struct DeviceData
  65.     {
  66.     int OutstandingIOs;
  67.     int Index;
  68.     int BoardNumber;
  69.     int RecieverRegistered;
  70.     LONG Random;
  71.     BYTE ActivityType;        /* 'T' = Transmit 'R' = Recieve 'B' = Both */
  72.     BYTE Name[80];
  73.     } Device[MAX_DEVICES];
  74.     
  75. /* NOTE: In order to prevent overflow of certain performance counters, byte
  76.    counts are maintained in units of 64 bytes (1 * 2^6) called "Chunks".
  77.    To convert Chunks to Kilobytes divide by 16.
  78.  */
  79. #define CHUNK_SIZE 64
  80. #define CHUNK_TO_KB 16
  81. #define MAX_PACKET_CHUNKS ( 1500 / CHUNK_SIZE ) 
  82. struct PerformanceData
  83.     {
  84.     LONG TotalReceivesCompleted;
  85.     LONG TotalChunksReceived;
  86.     LONG CurrentReceivesCompleted;
  87.     LONG CurrentChunksReceived;
  88.     LONG TotalSendsCompleted;
  89.     LONG TotalChunksSent;
  90.     LONG CurrentSendsCompleted;
  91.     LONG CurrentChunksSent;
  92.     } Performance[MAX_DEVICES];
  93.  
  94. struct PerformanceData Aggregate;
  95. int AggregateOutstandingIOs = 0;
  96.  
  97. int BoardToDeviceIndex[MAX_DEVICES];
  98.  
  99. BYTE CommonBuffer[2000];
  100. /* debug */
  101. eventcontrolblock *SendECB[MAX_DEVICES*32];
  102. LONG SendECBCount= 0;
  103. /* debug */
  104.  
  105. void
  106. NXSendCompletion( eventcontrolblock *currentECB );
  107.  
  108. LONG
  109. NXReceiveCompletion( eventcontrolblock *currentECB );
  110.  
  111. void
  112. MakeDeviceDescription( LONG BoardNumber, BYTE *buffer);
  113.  
  114. void
  115. NXercise();
  116.  
  117. void
  118. NXMonitor();
  119.  
  120. /* LSL Interface routines */
  121. LONG CLSLRegisterPreScanStack( int BoardNumber,
  122.                             int HandlerProcedure(),
  123.                             int ControlProcedure() );
  124.  
  125. LONG CLSLDeRegisterPreScanStack( int BoardNumber );
  126.  
  127. void *CLSLGetECB();
  128.  
  129. void CLSLReturnECB( void *ECB );
  130.  
  131. extern NXReceiveDone();
  132. extern NXSendDone();
  133. extern NXControl();
  134.  
  135. LONG
  136. StartProcedure(
  137.         LONG moduleHandle,
  138.         ScreenStruct *initializationErrorScreen,
  139.         BYTE *commandLine,
  140.         BYTE *loadDirectoryPath,
  141.         LONG unitializedDataLength,
  142.         LONG fileHandle,
  143.         LONG (*ReadRoutine)(LONG handle, LONG offset, BYTE *buffer, LONG length),
  144.         LONG customDataOffset,
  145.         LONG customDataSize)
  146. {
  147.     static BYTE nXerciseScreenName[] = "NX Screen";
  148.     int i;
  149.     BYTE *Token;
  150.     _UNUSED(commandLine);
  151.     _UNUSED(loadDirectoryPath);
  152.     _UNUSED(unitializedDataLength);
  153.     _UNUSED(fileHandle);
  154.     _UNUSED(ReadRoutine);
  155.     _UNUSED(customDataOffset);
  156.     _UNUSED(customDataSize);
  157.  
  158.     for (Token = commandLine; *Token != '\000'; Token++)
  159.         {
  160.         if (*Token == 'D') EnterDebugger();
  161.         }
  162.  
  163.     for ( i = 0; i < MAX_DEVICES; i++ ) BoardToDeviceIndex[i] = -1;
  164.  
  165.     CSetB( 0, CommonBuffer, sizeof( CommonBuffer ) );
  166.     CStrCpy( CommonBuffer, NX_SIGNATURE );
  167.         
  168.     stack = GetNonMovableMemory(STACK_SIZE, &stackSize);
  169.     if (stack == NULL)
  170.         {
  171.         OutputToScreen(initializationErrorScreen,
  172.             "NX: Unable to get memory for stack\r\n");
  173.         goto Error0;
  174.         }
  175.  
  176.     nXerciseModuleHandle = moduleHandle;
  177.     if (OpenScreen(nXerciseScreenName, &nXerciseScreen) != 0)
  178.         {
  179.         OutputToScreen(initializationErrorScreen,
  180.             "NX: Unable to open NX screen\r\n");
  181.         goto Error1;
  182.         }
  183.  
  184.     /* The variable stackSize contains the amount of memory actually
  185.        allocated for the stack, so use it instead of STACK_SIZE.*/
  186.  
  187.     /* this should be the last thing we do */
  188.     NXMonitorProcessID = CCreateProcess(NX_PRIORITY, NXMonitor,
  189.             stack + stackSize, stackSize, "NXMon");
  190.     while ( NXMonitorStatus == 'I') CRescheduleLast();
  191.     switch ( NXMonitorStatus)
  192.         {
  193.         case 'R':
  194.         break;
  195.         case 'S':
  196.         default:
  197.         OutputToScreen( systemConsoleScreen,
  198.                 "Failed to start NX monitor process\r\n" );
  199.         goto Error3;
  200.         }
  201.     return (0);
  202.  
  203. /* Error Recovery */
  204. Error3:
  205.     CloseScreen(nXerciseScreen);
  206. Error1:
  207.     ReturnNonMovableMemory(stack);
  208. Error0:
  209.     return (-1);
  210. }
  211.  
  212. void ExitProcedure(void)
  213. {
  214.     int i;
  215.         eventcontrolblock *ECBp;
  216.     
  217.     if ( NXMonitorProcessID != 0 ) CDestroyProcess( NXMonitorProcessID );
  218.  
  219.     if ( NXMonitorStatus != 'S' ) /* if not already stopped - stop */
  220.         {
  221.         NXMonitorStatus = 'S';
  222.         while ( AggregateOutstandingIOs != 0 ) CRescheduleLast();
  223.         if ( NXerciseProcessID != 0 ) CDestroyProcess( NXerciseProcessID );
  224.         }
  225.  
  226.     CloseScreen( nXerciseScreen );
  227.         
  228.         for (i=0; i < DeviceCount; i++)
  229.         {
  230.             if ( Device[i].RecieverRegistered )
  231.             {
  232.             CLSLDeRegisterPreScanStack (Device[i].BoardNumber);
  233.             }
  234.         while ( ECBList != NULL )
  235.             {
  236.         ECBp = ECBList;
  237.         ECBList = ECBp->RLink;
  238. /* debug */     if ( (LONG)ECBList == 0xFFFFFFFF ) EnterDebugger();
  239.         /* Return the ECB to the OS */
  240.         CLSLReturnECB( ECBp );
  241.         }
  242.         }
  243.     if ( NXStack != NULL ) ReturnNonMovableMemory( NXStack );
  244.     ReturnNonMovableMemory( stack );
  245.  
  246. }
  247.  
  248. void NXExit(void)
  249. {
  250.     KillMe((struct LoadDefinitionStructure *)nXerciseModuleHandle);
  251.  
  252.     /* Sleep forever until the exit procedure kills this process */
  253.     for (;;)
  254.         CSleepUntilInterrupt();
  255. }
  256.  
  257. void
  258. NXMonitor()
  259. {
  260.     long int LStatus;
  261.     int DeviceIndex;
  262.     LONG MaxPage;
  263.     LONG CurrentPage;
  264.     LONG FirstDevice;
  265.     LONG LastDevice;
  266.     LONG StartTime;
  267.     LONG IntervalStartTime;
  268.     LONG ElapsedSeconds;
  269.     LONG IntervalSeconds;
  270.     LONG Tenths;
  271.     LONG utilization;
  272.     LONG BytesPerIO;
  273.     LONG DeviceID;
  274.     LONG UpdateTicks;
  275.     eventcontrolblock *ECBp;
  276.     int i;
  277.     LONG chunks;
  278.     LONG packets;
  279.     BYTE Answer;
  280.     BYTE Dummy;
  281.     BYTE buffer[200];
  282.  
  283.     RandomNumberCount = sizeof( RandomNumber ) / 4;
  284.     /* Activate our screen */
  285.     Enable();
  286.     ActivateScreen(nXerciseScreen);
  287.  
  288.     /* Tell NXLoad we are Running */
  289.     NXMonitorStatus = 'R';
  290.  
  291.     /* Ask for packet size */
  292.     InputFromScreen( nXerciseScreen,
  293.         "RF",
  294.         2,
  295.         2,
  296.         buffer,
  297.         0L,
  298.         TRUE,
  299.         "F",
  300.         "Packet Length Type [F=Fixed R=Random]? " );
  301.     if ( buffer[0] == 'F' || buffer[0] == 'f' )
  302.         {
  303.     PromptForUnsignedNumber( nXerciseScreen,
  304.                  &BytesPerIO,
  305.                  CHUNK_SIZE,
  306.                  MAX_PACKET_CHUNKS * CHUNK_SIZE,
  307.                  10L,
  308.                  0L,
  309.                  TRUE,
  310.                  64L,
  311.                  "Bytes per packet [%d:%d]? ",
  312.                              CHUNK_SIZE,
  313.                  MAX_PACKET_CHUNKS * CHUNK_SIZE );
  314.     NXChunksPerIO = ( BytesPerIO + ( CHUNK_SIZE / 2 )) / CHUNK_SIZE;
  315.     if ( ( NXChunksPerIO * CHUNK_SIZE ) != BytesPerIO )
  316.         {
  317.         OutputToScreen( nXerciseScreen,
  318.             "Closest packet size avaiable %d selected\n\r",
  319.             NXChunksPerIO * 64 );
  320.         }
  321.     }
  322.     else
  323.         {
  324.         NXChunksPerIO = 0;
  325.     }
  326.  
  327.     /* Ask for queue depth */
  328.     PromptForUnsignedNumber( nXerciseScreen,
  329.                  &NXMaxSendsPerDevice,
  330.                  1L,
  331.                  MAX_SENDS_PER_DEVICE,
  332.                  10L,
  333.                  0L,
  334.                  TRUE,
  335.                  3L,
  336.                  "Number of concurrent sends to queue per device [1-%d]? ",
  337.                              MAX_SENDS_PER_DEVICE);
  338.  
  339.     /* Ask for update interval */
  340.     PromptForUnsignedNumber( nXerciseScreen,
  341.                  &NXUpdateInterval,
  342.                  1L,
  343.                  60L,
  344.                  10L,
  345.                  0L,
  346.                  TRUE,
  347.                  5L,
  348.                  "Screen update interval in seconds [1-60]? ");
  349.     ConvertSecondsToTicks( NXUpdateInterval, 0L, &UpdateTicks );
  350.  
  351.     /* Ask for selections or go */
  352.     DeviceCount = 0;
  353.     for (DeviceID = 0; DeviceID < MAX_DEVICES; DeviceID++)
  354.     {
  355.     /* test for presence of device */
  356.     if ( MLIDLoadedHandleTable[DeviceID] == 0 ) continue;
  357.     
  358.     MakeDeviceDescription( DeviceID, Device[DeviceCount].Name);
  359.     LStatus = PromptForYesOrNo( nXerciseScreen,
  360.                    0L,
  361.                    TRUE,
  362.                    "\r\nExercise %s ?",
  363.                    Device[DeviceCount].Name );
  364.     if ( LStatus )
  365.         {
  366.         /* Build map to map board number to device array index */
  367.         BoardToDeviceIndex[DeviceID] = DeviceCount;
  368.         
  369.         InputFromScreen( nXerciseScreen,
  370.             "TRB",
  371.             2,
  372.             2,
  373.             buffer,
  374.             0L,
  375.             TRUE,
  376.             "B",
  377.             "Device Activity [T=Transmit R=Recieve B=Both]? " );
  378.  
  379.             Device[DeviceCount].Index = DeviceCount;
  380.             Device[DeviceCount].BoardNumber = DeviceID;
  381.             Device[DeviceCount].ActivityType = buffer[0];
  382.             Device[DeviceCount].Random = 0;
  383.             Device[DeviceCount].OutstandingIOs = 0;
  384.         Device[DeviceCount].RecieverRegistered = 0;
  385.  
  386.         if ( Device[DeviceCount].ActivityType != 'T' ) /* Recieving ? */
  387.              {
  388.          /* Register stack */
  389.         if ( CLSLRegisterPreScanStack( DeviceID, NXReceiveDone, NXControl ) == 0 )
  390.             {
  391.             Device[DeviceCount].RecieverRegistered = 1;
  392.             }
  393.         else
  394.             {
  395.             OutputToScreen( nXerciseScreen, "NX Could not register PreScan reciever for device\r\n");
  396.             }
  397.          }
  398.         if ( Device[DeviceCount].ActivityType != 'R' ) /* Transmitting? */
  399.              {
  400.                 for ( i = 0; i < NXMaxSendsPerDevice; i++ )
  401.             {
  402.             /* Get an ECB for sending from the OS */
  403.             while ( ( ECBp = CLSLGetECB() ) == NULL )
  404.                 {
  405. /*
  406.                 OutputToScreen( nXerciseScreen, "NX Could not get a send ECB - trying again\r\n");
  407. */
  408.                     Delay ( 5 );
  409.                     }             
  410.  
  411. /* debug */
  412. SendECB[SendECBCount] = ECBp;
  413. SendECBCount++;
  414. /* debug */
  415.                 /* Link the ECB into the available queue for the device*/
  416.             ECBp->RLink = ECBList;
  417.             ECBList = ECBp;
  418. /* debug */     if ( (LONG)ECBList == 0xFFFFFFFF ) EnterDebugger();
  419.             /* Setup the send ECB */
  420.             ECBp->RESRAddress = (LONG)&NXSendDone;
  421.             ECBp->RLogicalID = 0;
  422.             ECBp->RImmediateAddress[0] = 0xff;
  423.             ECBp->RImmediateAddress[1] = 0xff;
  424.             ECBp->RImmediateAddress[2] = 0xff;
  425.             ECBp->RImmediateAddress[3] = 0xff;
  426.             ECBp->RImmediateAddress[4] = 0xff;
  427.             ECBp->RImmediateAddress[5] = 0xff;
  428.             ECBp->RSocket = 0;
  429.             ECBp->RPacketLength = 0;
  430.             ECBp->RFragmentCount = 1;
  431.             ECBp->RPacketOffset = (LONG)CommonBuffer;
  432.             ECBp->RPacketSize = 0;
  433.             }
  434.             }        
  435.         /* Clear performance information */
  436.         Performance[DeviceCount].TotalReceivesCompleted = 0;
  437.         Performance[DeviceCount].TotalChunksReceived = 0;
  438.         Performance[DeviceCount].CurrentReceivesCompleted = 0;
  439.         Performance[DeviceCount].CurrentChunksReceived = 0;
  440.         Performance[DeviceCount].TotalSendsCompleted = 0;
  441.         Performance[DeviceCount].TotalChunksSent = 0;
  442.         Performance[DeviceCount].CurrentSendsCompleted = 0;
  443.         Performance[DeviceCount].CurrentChunksSent = 0;
  444.  
  445.         DeviceCount++;
  446.         }
  447.     }
  448.     /* Zero aggregate preformance numbers */
  449.  
  450.     Aggregate.TotalReceivesCompleted = 0;
  451.     Aggregate.TotalChunksReceived = 0;
  452.     Aggregate.CurrentReceivesCompleted = 0;
  453.     Aggregate.CurrentChunksReceived = 0;
  454.     Aggregate.TotalSendsCompleted = 0;
  455.     Aggregate.TotalChunksSent = 0;
  456.     Aggregate.CurrentSendsCompleted = 0;
  457.     Aggregate.CurrentChunksSent = 0;
  458.     AggregateOutstandingIOs = 0;
  459.  
  460.     /* Make sure at least one Device is selected */
  461.  
  462.     if ( DeviceCount < 1 )
  463.     {
  464.     OutputToScreen( nXerciseScreen,
  465.             "No Devices selected\r\n" );
  466.     Delay( 91 );
  467.     NXExit();
  468.     }
  469.  
  470.     /* Start NXercise */
  471.     NXStack = GetNonMovableMemory( STACK_SIZE,
  472.                         &NXActualStackSize );
  473.     if ( NXStack == NULL)
  474.     {
  475.     OutputToScreen ( nXerciseScreen,
  476.             "Insufficient memory to start NX subprocess\r\n");
  477.     Delay( 91 );
  478.     NXExit();
  479.     }
  480.     NXerciseProcessID = CCreateProcess( NX_PRIORITY - 1,
  481.                     NXercise,
  482.                     NXStack + NXActualStackSize,
  483.                     NXActualStackSize,
  484.                     "NXerci");
  485.     /* Compute pages of displays */
  486.     MaxPage = ( DeviceCount / DEVICES_PER_PAGE ) + 1;
  487.     CurrentPage = 1;
  488.     /* Clear the Screen and setup the title */
  489.     ClearScreen( nXerciseScreen );
  490.     PositionOutputCursor( nXerciseScreen, 0, 0 );
  491.     OutputToScreen( nXerciseScreen,
  492.         "NetFRAME Network Test with %d Sends queued per device  Page %d of %d",
  493.         NXMaxSendsPerDevice,
  494.                 CurrentPage,
  495.                 MaxPage );
  496.  
  497.     /* Note the starting time for later computations */
  498.     StartTime = CurrentTime;
  499.  
  500.     while (1)
  501.     {
  502.     /* Sleep for update interval */
  503.         IntervalStartTime = CurrentTime;
  504.     Delay( UpdateTicks );
  505.     /* Test for keyboard key */
  506.     if ( CheckKeyStatus( nXerciseScreen ) )
  507.         {
  508.         /* Get the key and process it */
  509.         GetKey( nXerciseScreen, &Dummy, &Answer, &Dummy, &Dummy, 0L );
  510.             if ( Answer == 'Q' || Answer =='q' )
  511.                 {
  512.             PositionOutputCursor( nXerciseScreen, 24, 0 );
  513.             LStatus = PromptForYesOrNo( nXerciseScreen,
  514.                    0L,
  515.                    TRUE,
  516.                    "Exit Network Exerciser? " );
  517.             if ( LStatus )
  518.             {
  519.             NXMonitorStatus = 'P';
  520.             }
  521.                 }
  522.             else
  523.                 {
  524.                 if ( Answer > '0' && Answer <= '9' )
  525.                     {
  526.                     i = Answer - '0';
  527.                     if ( i <= MaxPage )
  528.                         {
  529.                         CurrentPage = i;
  530.                         ClearScreen( nXerciseScreen );
  531.                         PositionOutputCursor( nXerciseScreen, 0, 0 );
  532.                         OutputToScreen( nXerciseScreen,
  533.                 "NetFRAME Network Test with %d Sends queued per device  Page %d of %d",
  534.                 NXMaxSendsPerDevice,
  535.                         CurrentPage,
  536.                         MaxPage );
  537.                         }
  538.                     else RingTheBell();
  539.                     }
  540.                 else RingTheBell();
  541.                 }    
  542.         }
  543.     /* Test for requested stop */
  544.     if ( NXMonitorStatus == 'P' )
  545.         {
  546.         while ( AggregateOutstandingIOs != 0 ) CRescheduleLast();
  547.         if ( NXerciseProcessID != 0 )
  548.             {
  549.         CDestroyProcess( NXerciseProcessID );
  550.             NXerciseProcessID = 0;
  551.         }
  552.         NXMonitorStatus = 'S';      /* Say we are stopped */
  553.         ReturnNonMovableMemory( NXStack );
  554.         NXStack = NULL;
  555.         NXExit();
  556.         }
  557.     /* Compute and display the numbers */
  558.     ConvertTicksToSeconds( ( CurrentTime - StartTime ),
  559.                    &ElapsedSeconds,
  560.                    &Tenths );
  561.     ConvertTicksToSeconds( ( CurrentTime - IntervalStartTime ),
  562.                    &IntervalSeconds,
  563.                    &Tenths );
  564.         /* Update cumulative statistics */
  565.     for ( DeviceIndex = 0; DeviceIndex < DeviceCount; DeviceIndex++ )
  566.         {
  567.         chunks = Performance[DeviceIndex].CurrentChunksSent;
  568.         Performance[DeviceIndex].TotalChunksSent += chunks;
  569.         Aggregate.CurrentChunksSent += chunks;
  570.         packets = Performance[DeviceIndex].CurrentSendsCompleted;
  571.         Performance[DeviceIndex].TotalSendsCompleted += packets;
  572.         Aggregate.CurrentSendsCompleted += packets;
  573.         chunks = Performance[DeviceIndex].CurrentChunksReceived;
  574.         Performance[DeviceIndex].TotalChunksReceived += chunks;
  575.         Aggregate.CurrentChunksReceived += chunks;
  576.         packets = Performance[DeviceIndex].CurrentReceivesCompleted;
  577.         Performance[DeviceIndex].TotalReceivesCompleted += packets;
  578.         Aggregate.CurrentReceivesCompleted += packets;
  579.         }
  580.         /* Now roll up the aggregate totals */
  581.         Aggregate.TotalChunksSent += Aggregate.CurrentChunksSent;
  582.         Aggregate.TotalChunksReceived += Aggregate.CurrentChunksReceived;
  583.     Aggregate.TotalSendsCompleted += Aggregate.CurrentSendsCompleted;
  584.     Aggregate.TotalReceivesCompleted += Aggregate.CurrentReceivesCompleted;
  585.  
  586.     PositionOutputCursor( nXerciseScreen, 1, 0 );
  587.     OutputToScreen( nXerciseScreen, "%s\r\n%s\n\r",
  588.     "    Device            Cur. Send    Cur. Recv.   Ave. Send    Ave. Recv.",
  589.     "     Name             KB/s  Pkt/s  KB/s  Pkt/s  KB/s  Pkt/s  KB/s  Pkt/s" );
  590.     /*                     99999 99999  99999 99999  99999 99999  99999 99999 */
  591.         FirstDevice = ( CurrentPage - 1 ) * DEVICES_PER_PAGE;
  592.         /* note - LastDevice is really last Device index (0 based) plus 1) */
  593.         if ( CurrentPage == MaxPage ) 
  594.             {
  595.             LastDevice = DeviceCount;
  596.             }
  597.         else
  598.             {
  599.             LastDevice = CurrentPage * DEVICES_PER_PAGE;
  600.             }
  601.     for ( DeviceIndex = FirstDevice; DeviceIndex < LastDevice; DeviceIndex++ )
  602.         {
  603.         OutputToScreen( nXerciseScreen, "%-20.20s ", Device[DeviceIndex].Name );
  604.         OutputToScreen( nXerciseScreen, "%5d %5d  %5d %5d  %5d %5d  %5d %5d\r\n",
  605.             ( Performance[DeviceIndex].CurrentChunksSent / CHUNK_TO_KB ) / IntervalSeconds,
  606.             ( Performance[DeviceIndex].CurrentSendsCompleted ) / IntervalSeconds,
  607.             ( Performance[DeviceIndex].CurrentChunksReceived / CHUNK_TO_KB ) / IntervalSeconds,
  608.             ( Performance[DeviceIndex].CurrentReceivesCompleted ) / IntervalSeconds,
  609.             ( Performance[DeviceIndex].TotalChunksSent / CHUNK_TO_KB ) / ElapsedSeconds,
  610.             ( Performance[DeviceIndex].TotalSendsCompleted ) / ElapsedSeconds,
  611.             ( Performance[DeviceIndex].TotalChunksReceived / CHUNK_TO_KB ) / ElapsedSeconds,
  612.             ( Performance[DeviceIndex].TotalReceivesCompleted ) / ElapsedSeconds);
  613.         }
  614.             
  615.         /* Aggregate numbers */
  616.     OutputToScreen( nXerciseScreen, "\r\n" );
  617.     OutputToScreen( nXerciseScreen, "%-20.20s "," All Devices" );
  618.     OutputToScreen( nXerciseScreen, "%5d %5d  %5d %5d  %5d %5d  %5d %5d\r\n",
  619.         ( Aggregate.CurrentChunksSent / CHUNK_TO_KB ) / IntervalSeconds,
  620.         ( Aggregate.CurrentSendsCompleted ) / IntervalSeconds,
  621.         ( Aggregate.CurrentChunksReceived / CHUNK_TO_KB ) / IntervalSeconds,
  622.         ( Aggregate.CurrentReceivesCompleted ) / IntervalSeconds,
  623.         ( Aggregate.TotalChunksSent / CHUNK_TO_KB ) / ElapsedSeconds,
  624.         ( Aggregate.TotalSendsCompleted ) / ElapsedSeconds,
  625.         ( Aggregate.TotalChunksReceived / CHUNK_TO_KB ) / ElapsedSeconds,
  626.         ( Aggregate.TotalReceivesCompleted ) / ElapsedSeconds);
  627.     OutputToScreen( nXerciseScreen, "\r\n" );
  628.  
  629.     /* Utilization */
  630.     utilization = 100 - ((NumberOfPollingLoops * 100 +
  631.             (MaximumNumberOfPollingLoops >> 1)) / MaximumNumberOfPollingLoops);
  632.     OutputToScreen( nXerciseScreen, "Server utilization %6d%%\r\n", utilization);
  633.  
  634.         /* Instructions */
  635.     OutputToScreen( nXerciseScreen, "Q to quit or page number to view\n\r" );
  636.  
  637.         /* Zero current counts */
  638.     for ( DeviceIndex = 0; DeviceIndex < DeviceCount; DeviceIndex++ )
  639.         {
  640.         Performance[DeviceIndex].CurrentReceivesCompleted = 0;
  641.         Performance[DeviceIndex].CurrentChunksReceived = 0;
  642.         Performance[DeviceIndex].CurrentSendsCompleted = 0;
  643.         Performance[DeviceIndex].CurrentChunksSent = 0;
  644.             }
  645.     Aggregate.CurrentReceivesCompleted = 0;
  646.     Aggregate.CurrentChunksReceived = 0;
  647.     Aggregate.CurrentSendsCompleted = 0;
  648.     Aggregate.CurrentChunksSent = 0;
  649.  
  650.     }
  651. }
  652.  
  653. void
  654. NXercise()
  655. {
  656.     int Length;
  657.     LONG LStatus;
  658.     int CurrentDevice = 0;
  659.  
  660.     LONG SendCount = 0;
  661.     LONG BackToBackSends = 0;
  662.     register eventcontrolblock *ECBp;
  663.     register struct DeviceData *DeviceP;
  664.     struct DeviceData *LastDeviceP;
  665.     struct DeviceData *WrapDeviceP;
  666.  
  667.     DeviceP = &Device[0];
  668.     WrapDeviceP = &Device[DeviceCount];
  669.     LastDeviceP = &Device[0];
  670.     
  671.     while (1)
  672.     {
  673.     if ( NXMonitorStatus != 'R' )   /* If not running go to sleep forever */
  674.                     /* and wait to be destroyed */
  675.         {
  676.         while (1) CSleepUntilInterrupt();
  677.         }
  678.  
  679.     if ( DeviceP->ActivityType != 'R' ) /* if T or B */
  680.         {
  681.         if ( DeviceP->OutstandingIOs < NXMaxSendsPerDevice )
  682.         {
  683.                 BackToBackSends++;
  684.         SendCount++;
  685.  
  686.         /* Start another IO */
  687.         if ( NXChunksPerIO == 0 )
  688.             {
  689.             /* Random Length Packets */
  690.     
  691.             Length = ( ( RandomNumber[DeviceP->Random] % ( MAX_PACKET_CHUNKS - 1 ) ) + 1 ) * CHUNK_SIZE ;
  692.             DeviceP->Random++;
  693.             if ( DeviceP->Random == RandomNumberCount )
  694.                         DeviceP->Random = 0;
  695.             }
  696.         else
  697.             {
  698.             Length = NXChunksPerIO * CHUNK_SIZE;
  699.             }
  700.  
  701.         /* Build a physical I/O request */
  702.                 ECBp = ECBList;
  703.         ECBList = ECBp->RLink;
  704. /* debug */     if ( (LONG)ECBList == 0xFFFFFFFF ) EnterDebugger();
  705. /* debug */
  706.     {
  707.     int BAD, i;
  708.     BAD = -1;
  709.     for ( i = 0; i < SendECBCount; i++ )
  710.         {
  711.     if ( SendECB[i] == ECBp )
  712.         {
  713.         BAD = 0;
  714.         break;
  715.         }
  716.     }
  717.     if ( BAD ) EnterDebugger();
  718.     BAD = -1;
  719.     if ( ECBList != NULL )
  720.         {
  721.         for ( i = 0; i < SendECBCount; i++ )
  722.             {
  723.         if ( SendECB[i] == ECBList )
  724.             {
  725.             BAD = 0;
  726.             break;
  727.             }
  728.         }
  729.         if ( BAD ) EnterDebugger();
  730.     }
  731.     };
  732. /* debug */
  733.         ECBp->RPacketLength = Length;
  734.         ECBp->RPacketSize = Length;
  735.         ECBp->RFragmentCount = 1;
  736.         ECBp->RBoardNumber = DeviceP->BoardNumber;
  737.         ECBp->RESRBXValue = DeviceP->Index;
  738.         DeviceP->OutstandingIOs++;
  739.         AggregateOutstandingIOs++;
  740.             /* Send the ECB */
  741.         LStatus = CLSLSendPacket( ECBp );
  742.                 if ( LStatus != 0 )
  743.             {
  744.                     OutputToScreen( nXerciseScreen, "Send failed - Status 0x%x" );
  745.                 DeviceP->OutstandingIOs--;
  746.             AggregateOutstandingIOs--;
  747.             }
  748.         }
  749.         }
  750.     /* Look at the next device */
  751.     DeviceP++;
  752.     if ( DeviceP == WrapDeviceP )    /* Have all devices been tried */
  753.         {
  754.         DeviceP = &Device[0];    /* Wrap the device pointer */
  755.         if ( SendCount == 0 )    /* Was anything send on this pass? */
  756.             {
  757.                 Disable();          /* No, Nothing could be sent */
  758.         NXSleeping = -1;    /* Going to sleep */
  759.             CSleepUntilInterrupt();
  760.         NXSleeping = 0;        /* Now awake */
  761.         NXWakeRequested = 0;
  762.         Enable();
  763.         BackToBackSends = 0;    /* Note we have taken a break */
  764.         }
  765.         else
  766.             {                   /* Yes, Something was sent - keep going */
  767.         SendCount = 0;
  768.         }
  769.         }
  770.         if ( BackToBackSends == 20 )    /* Do we need to take a break? */
  771.         {
  772.         CRescheduleLast();        /* Give someone else a chance */
  773.         BackToBackSends = 0;    /* Note we have taken a break */
  774.         }
  775.         }
  776. }
  777.  
  778. void
  779. NXSendCompletion( eventcontrolblock *currentECB )
  780. {
  781.     int i;
  782.     int chunks;
  783.     register eventcontrolblock *ECBp;
  784.  
  785. /* debug */
  786.     int BAD = -1;
  787.     for ( i = 0; i < SendECBCount; i++ )
  788.         {
  789.     if ( SendECB[i] == currentECB )
  790.         {
  791.         BAD = 0;
  792.         break;
  793.         }
  794.     }
  795.     if ( BAD ) EnterDebugger();
  796. /* debug */
  797.  
  798.     i = currentECB->RESRBXValue;
  799.     chunks = ( currentECB->RPacketLength ) / CHUNK_SIZE;
  800.     /* Update individual device counts */
  801.     Performance[i].CurrentSendsCompleted++;
  802.     Performance[i].CurrentChunksSent += chunks;
  803.     
  804.     /* Put the request back on the send queue for the device */
  805.     --AggregateOutstandingIOs;
  806.     --Device[i].OutstandingIOs;
  807.     ECBp = ECBList;
  808.     ECBList = currentECB;
  809. /* debug */     if ( (LONG)ECBList == 0xFFFFFFFF ) EnterDebugger();
  810.     currentECB->RLink = ECBp;
  811.     if ( NXSleeping && (!NXWakeRequested) )
  812.         {
  813.     NXWakeRequested = -1;
  814.     CRescheduleFromInterrupt(NXerciseProcessID);
  815.         }
  816. }
  817.  
  818. LONG
  819. NXReceiveCompletion( eventcontrolblock *currentECB )
  820. {
  821.     int i;
  822.     int chunks;
  823. /* the board number to device index should be computed here */
  824.     i = BoardToDeviceIndex[currentECB->RBoardNumber];
  825.     if ( i != -1 ) /* Do we know about this board? */
  826.     {
  827.         chunks = ( currentECB->RPacketLength ) / CHUNK_SIZE;
  828.         
  829.         /* Update individual device counts */
  830.         Performance[i].CurrentReceivesCompleted++;
  831.         Performance[i].CurrentChunksReceived += chunks;
  832.             
  833.         /* Now return the receive ECB back to the pool if it's a NX packet */
  834.         if ( CStrCmp( (void *)currentECB->RPacketOffset, NX_SIGNATURE ) == 0 )
  835.         {
  836.         CLSLReturnECB( (void *)currentECB );
  837.         return ( 0 );    /* Don't try to route the packet */
  838.         }
  839.     }
  840.     return ( 1 ); /* Attempt to route the packet to a protocol stack */
  841. };
  842.  
  843. void
  844. MakeDeviceDescription(
  845.     LONG boardNumber,
  846.     BYTE *buffer)
  847. {
  848.     struct DriverConfigurationStructure *lanInfo;
  849.     BYTE *ptr;
  850.     lanInfo = MLIDConfigurationTable[boardNumber];
  851.     ptr = buffer;
  852.     /* LAN name */
  853.     sprintf(ptr, "%S", MLIDLoadedHandleTable[boardNumber]->LDFileName);
  854.     while (*ptr != '.' && *ptr != 0) ptr++;
  855.     *ptr++ = ' ';
  856.                    
  857.     *ptr++ = '[';
  858.  
  859.     if (PS2Flag)
  860.     {
  861.     /* slot */
  862.     sprintf(ptr, "slot=%x ", lanInfo->DSlot);
  863.     ptr = ptr + CStrLen(ptr);
  864.     }
  865.     else
  866.     {
  867.     /* IO ports */
  868.     if (lanInfo->DIOPortsAndRanges[1] > 0)    /* using IO port 0 */
  869.         {
  870.         sprintf(ptr, "port=%x ", lanInfo->DIOPortsAndRanges[0]);
  871.         ptr = ptr + CStrLen(ptr);
  872.         }
  873.     if (lanInfo->DIOPortsAndRanges[3] > 0)    /* using IO port 1 */
  874.         {
  875.         sprintf(ptr, "port=%x ", lanInfo->DIOPortsAndRanges[2]);
  876.         ptr = ptr + CStrLen(ptr);
  877.         }
  878.  
  879.     /* memory addresses */
  880.     if (lanInfo->DMemoryDecodeAndLength[0].LANMemoryAddress > 0)    /* using memory 0 */
  881.         {
  882.         sprintf(ptr, "mem=%x ",
  883.             lanInfo->DMemoryDecodeAndLength[0].LANMemoryAddress);
  884.         ptr = ptr + CStrLen(ptr);
  885.         if (lanInfo->DMemoryDecodeAndLength[1].LANMemoryAddress > 0)    /* using memory 1 */
  886.         {
  887.         sprintf(ptr, "mem=%x ",    lanInfo->DMemoryDecodeAndLength[1].LANMemoryAddress);
  888.         ptr = ptr + CStrLen(ptr);
  889.         }
  890.         }
  891.  
  892.         /* interrupts */
  893.     if (lanInfo->DIntLine[0] != 0xff)              /* first interrupt */
  894.         {
  895.         sprintf(ptr, "int=%x ", lanInfo->DIntLine[0]);
  896.         ptr = ptr + CStrLen(ptr);
  897.         if (lanInfo->DIntLine[1] != 0xff)          /* second interrupt */
  898.         {
  899.         sprintf(ptr, "int=%x ", lanInfo->DIntLine[1]);
  900.         ptr = ptr + CStrLen(ptr);
  901.         }
  902.         }
  903.  
  904.     /* DMA channels */
  905.     if (lanInfo->DDMALine[0] != 0xff)                /* first DMA */
  906.         {
  907.         sprintf(ptr, "dma=%x ", lanInfo->DDMALine[0]);
  908.         ptr = ptr + CStrLen(ptr);
  909.         if (lanInfo->DDMALine[1] != 0xff)             /* second DMA */
  910.         {
  911.         sprintf(ptr, "dma=%x ", lanInfo->DDMALine[1]);
  912.         ptr = ptr + CStrLen(ptr);
  913.         }
  914.         }
  915.     }
  916.     *(ptr - 1) = ']';
  917. }
  918.